/**
 * @file irq.h
 * @author lcz 3094655619@qq.com
 * @brief
 * @version 0.1
 * @date 2022-10-16
 *
 * @copyright Copyright (c) 2022
 *
 */

#ifndef IRQ_H
#define IRQ_H
#include "comm/types.h"
// define constant var
#define GATE_DESC_SIZE 128
#define IDE_TABLE_NR 128
// 中断号码
#define IRQ0_DE 0
#define IRQ1_DB 1
#define IRQ2_NMI 2
#define IRQ3_BP 3
#define IRQ4_OF 4
#define IRQ5_BR 5
#define IRQ6_UD 6
#define IRQ7_NM 7
#define IRQ8_DF 8
#define IRQ10_TS 10
#define IRQ11_NP 11
#define IRQ12_SS 12
#define IRQ13_GP 13
#define IRQ14_PF 14
#define IRQ16_MF 16
#define IRQ17_AC 17
#define IRQ18_MC 18
#define IRQ19_XM 19
#define IRQ20_VE 20
#define IRQ1_KEYBOARD 0x21 // 按键中断
#define IRQ14_HARDDISK_PRIMARY (0x20 + 14) // 主总线上的ATA磁盘中断

// TIME 放在time.h中

// 定义中断控制器 8259A芯片相关的宏
#define PIC_ICW1_ALWAYS_1 (1 << 4)
#define PIC_ICW1_ICW4 (1 << 0)
#define PIC_ICW4_8086 (1 << 0)
#define IRQ_PIC_START 0x20

#define PIC0_ICW1 0x20
#define PIC0_ICW2 0x21
#define PIC0_ICW3 0x21
#define PIC0_ICW4 0x21
#define PIC0_IMR 0x21

#define PIC1_ICW1 0xA0
#define PIC1_ICW2 0xA1
#define PIC1_ICW3 0xA1
#define PIC1_ICW4 0xA1
#define PIC1_IMR 0xA1

// define 8259 status port
#define PIC1_OCW2 0xa0 
#define PIC0_OCW2 0x20
#define PIC_OCW2_EOI (1 << 5)

// define interrupt gate attributes
#define GATE_P_PRESENT (1 << 15)
#define GATE_DPL0 (0 << 13)
#define GATE_DPL3 (3 << 13)
#define GATE_TYPE_INT (0xe << 8)


// 关于页异常信息打印的一些标志位

#define ERR_PAGE_P (1 << 0)
#define ERR_PAGE_WR (1 << 1)
#define ERR_PAGE_US (1 << 1)

#define ERR_EXT (1 << 0)
#define ERR_IDT (1 << 1)

typedef struct _exception_frame_t
{
    uint32_t gs, fs, es, ds;
    uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
    uint32_t num, error_code;
    // error code sometimes not push in stack, so not write
    uint32_t  eip, cs, eflags ;
    // 异常发生时，特权级改变，压栈的信息有所变化，
    // 修改结构如何真确解析我不是很理解，不切换的话不是少压了两个寄存器吗？
    // 那么地址结构体的解析不就出问题了吗？
    // 这里估计要是再特权级0发生异常或许有点小问题，个人理解，这一块最好好好理解一下就对了
    uint32_t esp3,ss3;
} exception_frame_t;

// define exception handle function,it will be use and install exception handle funcion of
// idt table
// define function pointer type, void is return type, (*irq_handler_t) is define point, use this funcion
// point use irq_handler_t,[exception_frame_t * frame] is parameter type and name
typedef void (*irq_handler_t)(exception_frame_t *frame);

// define idt struct
#pragma pack(1)
typedef struct _gate_desc_t
{
    uint16_t offset15_0;
    uint16_t selector;
    uint16_t attr;
    uint16_t offset31_16;
} gate_desc_t;
#pragma pack()

// declare function
void irq_init(void);
void gate_desc_set(gate_desc_t *desc, uint16_t selector, uint32_t offset, uint16_t attr);
int irq_install(int irq_num, irq_handler_t handler);
// declare exception handle function, they will be use in irq.c, use address in install 
void exception_handler_unknown(void);
void exception_handler_divider(void);
void exception_handler_Debug(void);
void exception_handler_NMI(void);
void exception_handler_breakpoint(void);
void exception_handler_overflow(void);
void exception_handler_bound_range(void);
void exception_handler_invalid_opcode(void);
void exception_handler_device_unavailable(void);
void exception_handler_double_fault(void);
void exception_handler_invalid_tss(void);
void exception_handler_segment_not_present(void);
void exception_handler_stack_segment_fault(void);
void exception_handler_general_protection(void);
void exception_handler_page_fault(void);
void exception_handler_fpu_error(void);
void exception_handler_alignment_check(void);
void exception_handler_machine_check(void);
void exception_handler_smd_exception(void);
void exception_handler_virtual_exception(void);



// declare about setting disable or enable interrupt function
// open and close the interrupt and setting PIC1_IMR register
void irq_disable_global(void);
void irq_enable_gloabl(void);
void irq_enable(int irq_num);
void irq_disable(int irq_num);

// report the 8259 interrupt hanle finished

void pic_send_eoi(int irq_num);

// 定义开关中断，临界资源保护部分的内容
typedef uint32_t irq_state_t;
irq_state_t irq_enter_protection(void);
void irq_leave_protection(irq_state_t state);

#endif 
